package cn.maihe.elg.operation.centers.hymake.channel.service;

import cn.maihe.elg.operation.centers.hymake.auth.HyMakeCenterAuthConfig;
import cn.maihe.elg.operation.centers.hymake.auth.HyMakeHeaderInfo;
import cn.maihe.elg.operation.centers.hymake.channel.HyMakeBaseChannelService;
import cn.maihe.elg.operation.centers.hymake.config.HyMakeInfoConfig;
import cn.maihe.elg.operation.centers.hymake.dto.channel.vo.xm.XMBondDownLoadReqDTO;
import cn.maihe.elg.operation.centers.hymake.dto.handler.vo.xm.XMBaseRespDTO;
import cn.maihe.elg.operation.centers.hymake.enums.HyMakeChannelMethod;
import cn.maihe.elg.operation.centers.hymake.enums.HyMakeRespCodeEnum;
import cn.maihe.elg.operation.centers.hymake.enums.XMChannelMethod;
import cn.maihe.elg.operation.common.TradeContext;
import cn.maihe.elg.operation.exception.CenterException;
import cn.maihe.elg.operation.model.dto.InnerBaseResp;
import cn.maihe.elg.operation.model.enums.AttachmentFileType;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.InnerRespCode;
import cn.maihe.elg.operation.repository.entity.AcceptOrderInfoDO;
import cn.maihe.elg.operation.repository.entity.BidCustomerDO;
import cn.maihe.elg.operation.service.business.BidCustomerService;
import cn.maihe.elg.operation.service.invoice.InvoiceInfoService;
import cn.maihe.elg.operation.service.order.AcceptOrderInfoService;
import cn.maihe.elg.operation.service.order.GuaranteeAttachmentInfoService;
import cn.maihe.elg.operation.supports.guarantee.enums.RespCode;
import cn.maihe.elg.operation.utils.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.util.EntityUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.core.io.FileSystemResource;
//import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 出函机构出函后通知 电子保函至平台侧
 * 出函机构（保险公司/银行）在出函后向电子保函平台推送电子保函的下载地址
 * @Author WJH
 * @Date 2021/04/21
 */
@Service
@Slf4j
public class XMPushUnsignedChannelService extends HyMakeBaseChannelService<XMBondDownLoadReqDTO, XMBaseRespDTO> {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private AcceptOrderInfoService acceptOrderInfoService;
    @Resource
    private GuaranteeAttachmentInfoService guaranteeAttachmentInfoService;
    @Resource
    private InvoiceInfoService invoiceInfoService;

    @Resource
    private HyMakeInfoConfig hyMakeInfoConfig;

    private XMChannelMethod methodEnum = XMChannelMethod.pushUnsignedFile;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private BidCustomerService bidCustomerService;

    public XMPushUnsignedChannelService(InvoiceInfoService invoiceInfoService) {
        this.invoiceInfoService = invoiceInfoService;
    }

    @Override
    protected HyMakeChannelMethod methodEnum() {
        return HyMakeChannelMethod.bondDownLoad;
    }

    public InnerBaseResp<String> bondDownload(Path docxPath, String acceptOrderNo) {

        AcceptOrderInfoDO acceptOrderInfo = acceptOrderInfoService.getByAcceptOrderNo(acceptOrderNo);
        Assert.notNull(acceptOrderInfo, "查无此受理订单记录");

        String fileMd5 = guaranteeAttachmentInfoService.getTypeAttachmentByAcceptOrderNo(acceptOrderNo, AttachmentFileType.TYPE_12).getFileMd5();

        HyMakeCenterAuthConfig hyMakeCenterAuthConfig = hyMakeInfoConfig.getAuthConfig(CenterNoEnum.XIAMEN);
//        BidCustomerDO bidCustomerDO = bidCustomerService.selectById(acceptOrderInfo.getBidCustomerId());
//        String appId = bidCustomerDO.getFollowId();
        String applyId = acceptOrderInfo.getCenterApplyId();


        Map<String, Object> reqBodyMap = new HashMap();
        reqBodyMap.put("APPID", hyMakeCenterAuthConfig.getCenterInfo().getAppId());
        reqBodyMap.put("APPLY_ID", applyId);

        reqBodyMap.put("FILEMD5", fileMd5);
        reqBodyMap.put("TIMESTAMP", DateUtil.getCurrentDate(DateUtil.FORMAT_DADETIME));

        String signature = hyMakeCenterAuthConfig.getHyMakeAuthorization().signature(reqBodyMap);


        reqBodyMap.put("SIGNATURE", signature);
        try {
            File file = docxPath.toFile();
//            byte[] bytes = Files.readAllBytes(docxPath);
            reqBodyMap.put("FILE", file);
        } catch (Exception e) {
            e.printStackTrace();
        }

        XMBondDownLoadReqDTO xmBondDownLoadReqDTO = JSONObject.parseObject(JSONObject.toJSONString(reqBodyMap), XMBondDownLoadReqDTO.class);
        InnerBaseResp<String> innerBaseResp;
        try {
            XMBaseRespDTO bizRespData = this.doRequest(CenterNoEnum.XIAMEN, xmBondDownLoadReqDTO, reqBodyMap);
            if (HyMakeRespCodeEnum.isSuccess(bizRespData.getCode())) {
                innerBaseResp = InnerBaseResp.success("");
            } else {
                innerBaseResp = InnerBaseResp.error("", bizRespData.getMessage());
            }
        } catch (Exception e) {
            log.error("3.1.3、推送电子保函申请单失败 >> [{}] 异常:{}", CenterNoEnum.XIAMEN.getCenterName(), e.getMessage(), e);
            innerBaseResp = InnerBaseResp.error("", "通知异常:" + e.getMessage());
        }

        return innerBaseResp;
    }

    public XMBaseRespDTO doRequest(CenterNoEnum centerNoEnum, XMBondDownLoadReqDTO reqDTO, Map<String, Object> reqBody) {
        HyMakeCenterAuthConfig authConfig = hyMakeInfoConfig.getAuthConfig(centerNoEnum);

        //构建上下文
        TradeContext context = new TradeContext(reqDTO);
        try {
            //请求参数校验
            ValidateUtil.validate(reqDTO);
        } catch (Exception e) {
            CenterException ce = buildCException(InnerRespCode.FAILURE_PARAM, e, "参数错误:");
            ElgLogger.error(log, l -> l.error("traceId={} => 中心[{}][{}]服务 参数校验失败：{}", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc(), ce.getMessage()));
            throw ce;
        }
        Gson gson = new GsonBuilder()
                .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY) // 保持原样
                .create();

        String json = gson.toJson(reqDTO);
//        String json = JSONObject.toJSONString(reqDTO);

//        HyMakeHeaderInfo hyMakeHeaderInfo = HyMakeHeaderInfo.builder()
//                .appid(authConfig.getCenterInfo().getAppId())
//                .requestid(IdGenerate.getIdStr())
//                .timestamp(String.valueOf(System.currentTimeMillis()))
//                .version(authConfig.getCenterInfo().getVersion())
//                .build();

        //请求渠道服务
        String reqUrl = this.buildReqUrl(authConfig);
        try {
            ElgLogger.info(log, l -> l.info("traceId={} => 中心[{}][{}]服务 请求报文：{}", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc(), json));
            ElgLogger.info(log, l -> l.info("traceId={} => 中心[{}][{}]服务 请求地址：{}", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc(), reqUrl));
//            HttpHeaders headers = new HttpHeaders();
//            BeanMap.create(hyMakeHeaderInfo).forEach((k, v) -> {
//                headers.add((String) k, (String) v);
//            });
            // 1. 创建 multipart 请求体
//            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();

            // 创建参数队列
//            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
//            builder.setCharset(Charset.forName("utf-8"));
//            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
//            builder.setContentType(ContentType.MULTIPART_FORM_DATA);
//            reqBody.forEach((key, value) -> {
//                if (value instanceof File) {
//                    if (value != null) {
//                        log.info("文件推送：文件路径：{}", ((File) value).getPath());
//                    }
//                    FileBody fileBody = value != null ? new FileBody((File) value, ContentType.MULTIPART_FORM_DATA, ((File) value).getName()) : null;
//                    if (fileBody != null) {
//                        builder.addPart(key, fileBody);
//                    }
//                } else {
//                    builder.addTextBody(key, value.toString(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
//                }
//            });
//
//            // 2. 设置请求头
//            HttpHeaders headers = new HttpHeaders();
//            headers.setContentType(MediaType.MULTIPART_FORM_DATA);  // 关键修改
//            headers.set("Charset", "UTF-8");
//
//            HttpEntity httpEntity = builder.build();
            // 3. 创建请求实体
//            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

//            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

//            HttpEntity<String> request = new HttpEntity<>(JSONObject.toJSONString(json));
//            ResponseEntity<XMBaseRespDTO> responseEntity = restTemplate.postForEntity(reqUrl, httpEntity, XMBaseRespDTO.class);
            //发送PostFormData请求
            String responseStr = HttpUtil.doPostFormData(reqUrl, reqBody);
            ElgLogger.info(log, l -> l.info("traceId={} <= 中心[{}][{}]服务 响应报文：{}", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc(), responseStr));
            XMBaseRespDTO xmBaseRespDTO = JSON.parseObject(responseStr, XMBaseRespDTO.class);

            if (responseStr == null) {
                throw new RuntimeException("响应报文为空");
            } else {
                //正常响应业务处理
                if (!xmBaseRespDTO.getSuccess()) {
                    throw new RuntimeException("渠道侧接收失败:[" + xmBaseRespDTO.getErrorCode() + "," + xmBaseRespDTO.getErrorDesc() + "]");
                }
//                ElgLogger.info(log, l -> l.info("traceId={} <= 中心[{}][{}]服务 响应报文：{}", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc(), this.toJsonString(xmBaseRespDTO)));
                ElgLogger.info(log, l -> l.info("traceId={} <= 中心[{}][{}]服务", context.getTraceId(), centerNoEnum.getCenterNo(), methodEnum().getDesc()));
                xmBaseRespDTO.setCode(HyMakeRespCodeEnum.SUCCESS.getRespCode());
                xmBaseRespDTO.setMessage(HyMakeRespCodeEnum.SUCCESS.getRespDesc());
                return xmBaseRespDTO;
            }

        } catch (Exception e) {
            CenterException ce = buildCException(InnerRespCode.FAILURE, e, "请求响应异常:");
            ElgLogger.error(log, l -> l.error("traceId={} <= 中心[{}][{}]服务 请求响应异常：{}", context.getTraceId(),
                    centerNoEnum.getCenterNo(), methodEnum().getDesc(), ce.getMessage()));
            throw ce;
        }

    }


    private String toJsonString(Object body) {
        if (body != null) {
            try {
                return objectMapper.writeValueAsString(body);
            } catch (JsonProcessingException e) {
                throw CenterException.exception("转换json字符串异常", e);
            }
        }
        return null;
    }


    private String buildReqUrl(HyMakeCenterAuthConfig authConfig) {
        String reUrl = null;
        String url = authConfig.getCenterInfo().getUrl().trim();
        if (url.endsWith("/")) {
            reUrl = url + methodEnum().getMethod();
        } else {
            reUrl = url + "/" + methodEnum().getMethod();
        }
        //若有特殊配置指定地址则已指定地址为准
        if (methodEnum == XMChannelMethod.pushUnsignedFile) {
            reUrl = url + XMChannelMethod.pushUnsignedFile.getMethod();
        }

        return reUrl;
    }
}
